//
//  BYImageHelper.m
//  demo36图片拼接
//
//  Created by bing on 16/1/6.
//  Copyright © 2016年 bing. All rights reserved.
//  

#import "BYImageHelper.h"
#import <zlib.h>

@implementation BYImageHelper

/*!
 *  @brief 拼接图片
 *
 *  @param topImage  上边的图片
 *  @param imageDown 下边的图片
 *
 *  @return 图片
 */
+ (UIImage *)stitchingImageWithInfo:(BYMergeInfo *)info {
    UIImage *newImage = nil;
    
    CGFloat width  = info.topImage.size.width;
    CGFloat height = info.topOffset + info.downImage.size.height - info.downOffset;
    CGSize size    = CGSizeMake(width, height);
    
    @autoreleasepool {
        UIGraphicsBeginImageContextWithOptions(size, NO, 0.0);
        
        CGRect topRect = CGRectMake(0, 0, width, info.topOffset);
        UIImage *topImage = [self subImage:info.topImage withRect:topRect];
        [topImage drawInRect:topRect];
        
        CGFloat downheight = info.downImage.size.height - info.downOffset;
        CGRect downRect = CGRectMake(0, info.downOffset, width, downheight);
        UIImage *downImage = [self subImage:info.downImage withRect:downRect];
        downRect = CGRectMake(0, info.topOffset, width, downheight);
        [downImage drawInRect:downRect];
        
        
        newImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
    }
    
    return newImage;
}

+ (UIImage *)subImage:(UIImage *)image withRect:(CGRect)rect {
    CGImageRef imageRef = CGImageCreateWithImageInRect(image.CGImage, rect);
    UIImage *result = [UIImage imageWithCGImage:imageRef];
    CGImageRelease(imageRef);
    return result;
}

/*!
 *  @brief 一般算法
 *
 *  @param topImage  上边图
 *  @param downImage 下边图
 *
 *  @return 拼接信息
 */
+ (BYMergeInfo *)computeMethod2MergeInfoWithTopImage:(UIImage *)topImage downImage:(UIImage *)downImage {
    
    NSArray *lines1 = [self getBitmapDataFromImage:topImage];
    NSArray *lines2 = [self getBitmapDataFromImage:downImage];
    
    // 将值作为矩阵元素,堆叠
    CGFloat topoffset   = 0;
    CGFloat downoffset  = 0;
    CGFloat length      = 0;
    
    // 顶部栏高度除去
    CGFloat barheight = 0;
    for (NSInteger i = barheight; i < lines1.count; i++) {
        long long value1 = [[lines1 objectAtIndex:i] longLongValue];
        
        for (NSInteger j = barheight; j < lines2.count; j++) {
            long long value2 = [[lines2 objectAtIndex:j] longLongValue];
            
            // 获取最长匹配
            if (value1 == value2) {
                NSInteger temp = 0, m = i, n = j;

                while ((value1 == value2) && m < lines1.count && n < lines2.count) {
                    value1 = [[lines1 objectAtIndex:m] longLongValue];
                    value2 = [[lines2 objectAtIndex:n] longLongValue];
                    if (temp > length) {
                        length      = temp;
                        topoffset   = m;
                        downoffset  = n;
                    }
                    temp++;
                    m++;
                    n++;
                }
                
            }
        }
    }
    
    BYMergeInfo *info   = [[BYMergeInfo alloc] init];
    info.topImage       = topImage;
    info.topOffset      = topoffset - length + 1;
    info.downImage      = downImage;
    info.downOffset     = downoffset - length + 1;
    return info;
}

/*!
 *  @brief 矩阵算法
 *
 *  @param topImage  顶部图片
 *  @param downImage 底部图片
 *
 *  @return 合并信息
 */
+ (BYMergeInfo *)computeMethod1MergeInfoWithTopImage:(UIImage *)topImage downImage:(UIImage *)downImage {
    
    NSArray *lines1 = [self getBitmapDataFromImage:topImage];
    NSArray *lines2 = [self getBitmapDataFromImage:downImage];
    
    // 矩阵
    int **matrix = (int **)malloc(lines1.count * sizeof(int *));
    for (int i = 0; i < lines1.count; i++) {
        matrix[i] = (int *)malloc(sizeof(int) * lines2.count);
    }
    
    // 列头
    long long value1 = [lines1.firstObject longLongValue];
    for (int i = 0; i < lines2.count; i++) {
        long long value = [[lines2 objectAtIndex:i] longLongValue];
        matrix[0][i] = (value == value1);
    }
    
    // 行头
    long long value2 = [lines2.firstObject longLongValue];
    for (int i = 0; i < lines1.count; i++) {
        long long value = [[lines1 objectAtIndex:i] longLongValue];
        matrix[i][0] = (value == value2);
    }
    
    // 将值作为矩阵元素,堆叠
    CGFloat topoffset   = 0;
    CGFloat downoffset  = 0;
    CGFloat length      = 0;
    for (NSInteger i = 1; i < lines1.count; i++) {
        long long value1 = [[lines1 objectAtIndex:i] longLongValue];
        
        for (NSInteger j = 1; j < lines2.count; j++) {
            long long value2 = [[lines2 objectAtIndex:j] longLongValue];
            
            // 行数据相等,累加前面数据
            if (value1 == value2) {
                int value = matrix[i-1][j-1] + 1;
                
                // 记录位置
                if (value > length) {
                    length      = value;
                    topoffset   = i;
                    downoffset  = j;
                }
                
                matrix[i][j] = value;
                
            } else {
                matrix[i][j] = 0;
            }
        }
    }

    for (int i = 0; i < lines1.count; i++) {
        free(matrix[i]);
    }
    free(matrix);
    
    BYMergeInfo *info   = [[BYMergeInfo alloc] init];
    info.topImage       = topImage;
    info.topOffset      = topoffset - length + 1;
    info.downImage      = downImage;
    info.downOffset     = downoffset - length + 1;
    return info;
}

/*!
 *  @brief 获取图片的每行像素数据
 *
 *  @param image 图片
 *
 *  @return 图片每行的元数据数组
 */
+ (NSArray *)getBitmapDataFromImage:(UIImage *)image {

    CGImageRef inImage    = image.CGImage;
    CFDataRef pixelData   = CGDataProviderCopyData(CGImageGetDataProvider(inImage));
    const UInt8 *data     = CFDataGetBytePtr(pixelData);
    NSInteger height      = CGImageGetHeight(inImage);
    NSInteger width       = CGImageGetWidth(inImage);
    
    NSMutableArray *lines = [NSMutableArray array];
    for (NSInteger offset = 0; offset < height; offset++) {
        NSData *cacheData = [NSData dataWithBytes:data + offset * width * 4
                                           length:width * 4];
        uLong print = crc32(0, [cacheData bytes], (uInt)[cacheData length]);
        [lines addObject:@(print)];
    }

    CFRelease(pixelData);
    
    return lines;
}

/*!
 *  @brief 精确匹配像素点
 *
 *  @param fromcolor color1
 *  @param toColor   color2
 *
 *  @return 结果
 */
+ (BOOL)Color:(UIColor *)fromcolor isEqual:(UIColor *)toColor {
    if (CGColorEqualToColor(fromcolor.CGColor, toColor.CGColor)) {
        return YES;
    }
    return NO;
}

/*!
 *  @brief 模糊匹配
 *
 *  @param fromColor color1
 *  @param toColor   color2
 *
 *  @return 结果
 */
+ (BOOL)Color:(UIColor *)fromColor isFuzzyEqual:(UIColor *)toColor {

    //获取颜色分量
    BYColor *fromcolor = [[BYColor alloc] init];
    const CGFloat *fromComponents = CGColorGetComponents(fromColor.CGColor);
    fromcolor.alpha = fromComponents[0];
    fromcolor.red   = fromComponents[1];
    fromcolor.green = fromComponents[2];
    fromcolor.blue  = fromComponents[3];
    
    BYColor *tocolor = [[BYColor alloc] init];
    const CGFloat *toComponents = CGColorGetComponents(toColor.CGColor);
    tocolor.alpha = toComponents[0];
    tocolor.red   = toComponents[1];
    tocolor.green = toComponents[2];
    tocolor.blue  = toComponents[3];
    
    //向量比较
    float difference = pow((fromcolor.red - tocolor.red), 2);
    difference += pow((fromcolor.green - tocolor.green), 2);
    difference += pow((fromcolor.blue - tocolor.blue), 2);
    difference = pow(difference, 0.5);
    if (difference < 85.0) {
        return YES;
    }
    
    return NO;
}

/*!
 *  @brief 获取图片摸个位置的颜色
 *
 *  @param location 位置
 *  @param image    图片
 *
 *  @return color
 */
+ (UIColor *)getPixelColorAtLocation:(CGPoint)location inImage:(UIImage *)image {

    UIColor *color;
    CGImageRef inImage   = image.CGImage;
    CGContextRef context = [self createRGBBitmapContextFromImage:inImage];

    if (context == NULL)
        return nil;
    
    size_t w    = CGImageGetWidth(inImage);
    size_t h    = CGImageGetHeight(inImage);
    CGRect rect = CGRectMake(0, 0, w, h);// {{0,0},{w,h}}
    
    CGContextDrawImage(context, rect, inImage);
    
    unsigned char *data = CGBitmapContextGetData(context);
    
    if (data != NULL) {
        NSInteger offset    = 4 * ((w * location.y) + round(location.x));
        NSInteger alpha     = data[offset];
        NSInteger red       = data[offset + 1];
        NSInteger green     = data[offset + 2];
        NSInteger blue      = data[offset + 3];
        
        color = [UIColor colorWithRed:(red/255.0) green:(green/255.0) blue:(blue/255.0) alpha:(alpha/255.0)];
    }
    
    CGContextRelease(context);
    
    if (data) {
        free(data);
    }
    
    return color;
}

/*!
 *  @brief 根据图片生成context
 *
 *  @param inImage 图片
 *
 *  @return contect
 */
+ (CGContextRef)createRGBBitmapContextFromImage:(CGImageRef)inImage {
    
    CGContextRef    context = NULL;
    CGColorSpaceRef colorSpace;
    NSInteger       bitmapByteCount;
    NSInteger       bitmapBytePerRow;
    void            *bitmapData;
    
    size_t pixelsWidth  = CGImageGetWidth(inImage);
    size_t pixelsHeight = CGImageGetHeight(inImage);
    
    bitmapBytePerRow    = pixelsWidth * 4;
    bitmapByteCount     = bitmapBytePerRow * pixelsHeight;
    colorSpace          = CGColorSpaceCreateDeviceRGB();
    
    if (colorSpace == NULL) {
        fprintf(stderr, "error alloc color space\n");
        return NULL;
    }
    
    bitmapData = malloc(bitmapByteCount);
    
    if (bitmapData == NULL) {
        fprintf(stderr, "memory not alloc");
        CGColorSpaceRelease(colorSpace);
        return NULL;
    }
    
    context = CGBitmapContextCreate(bitmapData,
                                    pixelsWidth,
                                    pixelsHeight,
                                    bitmapByteCount,
                                    bitmapBytePerRow,
                                    colorSpace,
                                    kCGImageAlphaPremultipliedFirst);
    
    if (context == NULL) {
        free(bitmapData);
        fprintf(stderr, "contect not create");
    }
    
    CGColorSpaceRelease(colorSpace);
    
    return context;
}

@end
